#include "command.h"

#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include "builtin.h"
#include "task.h"
#include "utility.h"
#include "stringtokenizer.h"

static bool should_background( char * command )
{
    char * temp = strdup( command );
    char * temp2 = NULL;

    char * pch = strtok( temp, " " );

    while ( pch != NULL ) {
        if ( temp2 != NULL )
            free( temp2 );
        temp2 = strdup( pch );
    }

    bool ret = ( temp2 == NULL || temp2[0] != '&' );

    if ( !ret )
        *( strrchr( command, '&' ) ) = ' ';

    free( temp );
    free( temp2 );

    return ret;
}

struct Command {
    struct Task ** tasks;
    char * command;
    size_t num_tasks;
};

static void command_free( struct Command * command )
{
    for ( size_t i = 0; i < command->num_tasks; i++ )
        task_free( command->tasks[i] );

    free( command->tasks );
    free( command );
}

static struct Command * command_parse( const char * command )
{
    struct Command * ret = malloc( sizeof( struct Command ) );

    char * temp = strdup( command );
    //bool background = should_background( temp );

    struct StringTokens * tokens = tokens_create( temp, "|" );

    ret->command = strdup( temp );
    ret->num_tasks = tokens_size( tokens );
    ret->tasks = malloc( sizeof(struct Task *) * ret->num_tasks );

    int pipes[512][2];

    if ( ret->num_tasks != 0 ) {
        for ( size_t i = 0; i < ret->num_tasks - 1; i++ ) {
            if ( pipe( pipes[i] ) < 0 )
                exit(1);
        }

        for( size_t i = 0; i < ret->num_tasks; i++ ) {
            ret->tasks[i] = task_create( tokens_get( tokens, i ),
                                        ( i == 0 ) ? STDIN_FILENO : pipes[i - 1][0],
                                        ( i == ret->num_tasks - 1 ) ? STDOUT_FILENO : pipes[i][1] );
        }
    }

    tokens_free( tokens );
    free( temp );

    return ret;
}

static void command_exec( struct Command * command )
{
    for( size_t i = 0; i < command->num_tasks; i++ ) {

        if ( !task_fork_needed( command->tasks[i] ) && command->num_tasks == 1 ) {
            task_run_unforked( command->tasks[i] );
        } else {
            if ( fork() == 0 ) {
                task_run_forked( command->tasks[i] );
            } else {
                wait( 0 );
            }
        }

    }
}

void command_run(const char * ch)
{
    struct Command * command = command_parse( ch );
    command_exec( command );
    command_free( command );
}
